home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
inet
/
internet-drafts
/
draft-ietf-sip-bsd-api-00.txt
< prev
next >
Wrap
Text File
|
1993-04-05
|
23KB
|
580 lines
Internet Engineering Task Force Robert E. Gilligan
INTERNET-DRAFT Sun Microsystems, Inc.
March 26, 1993
SIP Program Interfaces for BSD Systems
Abstract
In order to implement the Simple Internet Protocol (SIP) [1] in an
operating system based on 4.x BSD, changes must be made to some of the
application program interfaces (APIs). TCP/IP applications written for
BSD-based operating systems have in the past enjoyed a high degree of
portability because most of the systems derived from BSD provide the
same API, known informally as "the socket interface". We would like the
same portability to be possible with SIP applications. This memo
presents a set of changes to the BSD socket API to support SIP. The
changes include a new data structure to carry 64-bit SIP addresses, a
new name to address translation library function, new address conversion
functions, and some new setsockopt() options. The changes are designed
to be minimal and to provide source and binary compatibility for
existing applications.
Status of this Memo
Internet Drafts are working documents of the Internet Engineering Task
Force (IETF), its Areas, and its Working Groups. Note that other groups
may also distribute working documents as Internet Drafts.
Internet Drafts are draft documents valid for a maximum of six months.
This Internet Draft expires on September 26, 1993. Internet Drafts may
be updated, replaced, or obsoleted by other documents at any time. It is
not appropriate to use Internet Drafts as reference material or to cite
them other than as a "working draft" or "work in progress."
Please check the I-D abstract listing contained in each Internet Draft
directory to learn the current status of this or any other Internet
Draft.
Distribution of this memo is unlimited.
1. Introduction.
The most visible feature of SIP is its extension of the length of an IP
address from 32 bits to 64 bits. The APIs that the BSD system provides
make the size of an IP address quite visible to an application.
Virtually all TCP/IP applications for BSD-based systems have knowledge
of the size of an IP address. Generally speaking, those parts of the
API that make addresses visible need to be changed. This paper presents
a first attempt to define the API changes needed to support SIP in BSD
systems. These APIs are expected to evolve as we gain more
implementation experience.
2. Design considerations
There are two important considerations in designing changes to these
well-worn APIs. First, the modified API should provide both source and
binary compatibility for programs written to the existing API. That is,
exiting program binaries should continue to operate when run on or
re-compiled and run a system supporting the new APIs. The API changes
for SIP should not cause existing program binaries to break, nor should
they cause programs written to the existing APIs to fail to compile or
break when re-compiled.
Second, the changes should be as minimal as possible and should make it
as easy as possible to change an existing application to be SIP
knowledgeable.
2.1 What needs to be changed
Since their address arguments are all opaque pointers, none of the
socket system calls need to changed directly.
The in_addr structure is 4-bytes long and can not be changed without
breaking applications. The sockaddr_in structure, which is passed into
and returned by the socket functions, contains 8 bytes of unused space
which can be used to hold a SIP address without incompatibility.
The gethostbyaddr() function includes an address type argument, so this
function does not need to be changed. However, the gethostbyname()
function does not include a type argument, and most applications that
use it assume that the address array that it returns consists of 4-byte
IP addresses. Thus a new function similar to gethostbyname(), but
knowledgeable of SIP addresses, must be defined.
Finally, a new interface is needed in order to set the SIP flow ID. The
most straightforward way to do this is to define new setsockopt()
options at the IPPROTO_IP level.
2.2 Implementation experience
The Sun IPAE/SIP prototype exposed some of the issues in designing a
compatible interface. The initial prototype passed SIP addresses
between the kernel and applications using the sockaddr_in structure with
the sin_family field set to AF_INET. The 8-byte SIP address occupied
the 4 bytes of the "sin_addr" field plus the first 4 bytes of the
"sin_zero" field. The kernel distinguished between 8-byte SIP addresses
and 4-byte IPv4 addresses passed in by checking the sin_zero field. If
sin_zero was zero, the kernel would assume that the sin_addr field held
a 4-byte IPv4 address. If sin_zero was non-zero, it would assume that
an 8-byte SIP address was being passed in.
While this technique works for most existing applications, we discovered
that some applications do not set the sin_zero field of the sockaddr_in
structure to zero. Thus we concluded that it would be unworkable in the
general case and that some specific indication was needed to distinguish
a 8-byte SIP address from a 4-byte IPv4 address in a sockaddr_in
structure.
Another useful lesson learned from the initial Sun implementation was
that the form of addresses (IPv4 or SIP) passed in and out of the socket
functions did not always need to constrain the form of packets (IPv4,
IPAE or SIP) transmitted or received. For example, a pre-existing TCP
server application that knows nothing of SIP could accept a connection
that was transmitting and receiving TCP segments encapsulated within SIP
packets. Because SIP and IPv4 addresses are mappable, the accept()
system call can return to the application the client's address as a
4-byte IPv4 address.
What does matter, however, is that pre-existing applications never be
given address structures that they don't understand. We found that the
most convenient way for the kernel to decide what form of address to
pass back to applications was to look at the form of addresses passed
in. That is, if an application passes in IPv4 form addresses, then it
should always be given IPv4 form addresses. If the application passes
in SIP form addresses, the kernel can return SIP form addresses to the
application.
3. Interface specification
3.1. New address family
We define a address family macro in <sys/socket.h>:
#define AF_SIP 24 /* Simple Internet Protocol */
The AF_SIP definition is used only to distinguish between the original
AF_INET form of the sockaddr_in structure, and a new form that we have
defined. Thus there is no corresponding PF_SIP definition.
3.2 Sockaddr_in structure
The sockaddr_in structure is used in the socket system calls to pass
addresses between the application and the kernel. Keeping the
sockaddr_in structure the same size is necessary to provide binary
compatibility for existing IPv4 applications. We can avoid changing the
size of the sockaddr_in structure by appropriating the currently unused
sin_zero field to hold the 64 bit SIP address.
We can add a structure element for the SIP address without changing the
original structure definition by just adding two new macros. The
resulting definition in the <netinet/in.h> header file is:
struct sockaddr_in {
short sin_family;
u_short sin_port;
in_addr sin_addr;
char sin_zero[8];
}
#define sip_addr sin_zero
#define sip_zero sin_addr
The value of the sin_family field determines whether the sockaddr_in
structure is holding a 32 bit IPv4 address or a 64 bit SIP address. The
sin_family field may have one of two values: AF_INET or AF_SIP. If
sin_family is AF_SIP, then the sip_addr field contains a 8-byte SIP
address and the sip_zero field must be set to zero. If the sin_family
field is AF_INET, then the sockaddr_in keeps its original semantics: The
sin_addr field contains a 4-byte IPv4 address and the sin_zero field
must be set to zero.
We refer to the the two variants as the "AF_INET form" or the "AF_SIP
form" of the sockaddr_in structure.
The two structure layouts can be understood better when viewed
graphically. This is the AF_INET form of the sockaddr_in structure:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AF_INET | port number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IPv4 address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ all zero bits +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
And this is the layout of the AF_SIP form of the sockaddr_in structure:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AF_SIP | port number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| all zero bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ SIP address +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
We considered an alternative form that overlays the high-order four
bytes of the SIP address with sin_addr. The form presented has a few
advantages:
- The SIP address is aligned on a 64-bit boundary within the
structure.
- The kernel can do some consistency checking on AF_SIP addresses
passed in. Because the sip_zero field, which overlays the
sin_addr field, must always zero, the kernel can detect cases
where the application incorrectly treats an AF_SIP form
sockaddr_in as an AF_INET form.
- The structure declaration is simpler than the alternative.
3.3 The socket functions
Even though we define a new address family for SIP, there is no change
to the way that applications get sockets. There is not a new "type" of
socket for SIP. SIP applications continue use AF_INET in the "domain"
argument (the first argument) of the socket() call. For example, to get
a TCP socket, a SIP application would call:
s = socket (AF_INET, SOCK_STREAM, 0);
and to get a UDP socket, a SIP application would call:
s = socket (AF_INET, SOCK_DGRAM, 0);
Once the application has a socket, it may use either the AF_SIP or the
AF_INET form of the sockaddr_in structure in the system calls that pass
addresses in to the kernel.
The form of sockaddr_in structure returned to the application by the
socket functions is determined by the form of addresses passed in most
recently. For example, if an application uses an AF_SIP form address in
its bind() call, then a subsequent accept() call would return a
sockaddr_in structure in the AF_SIP form. If the application calls no
socket function that passes in an address before calling one that
returns an address, then that function returns an AF_INET form address.
The socket functions to which an application passes in an address
argument are:
bind()
connect()
sendto()
The socket functions that return an address to the application are:
accept()
recvfrom()
getpeername()
getsockname()
3.4 Sockets passed across exec()
Having two forms of sockaddr_in address that may be used interchageably
with all AF_INET sockets means that existing applications are supported
straightforwardly, and that new applications simply need to be written
to use the AF_SIP form of sockaddr_in. However, Unix allows open
sockets to be passed across an exec() call. Thus a newly written
application may find itself holding an open socket that was passed to it
via exec(), but not knowing what form of addresses that will be
returned. Similarly, a newly written SIP knowledgeable application may
wish to use AF_SIP form addresses in its bind() or connect() calls, and
then pass the socket to a pre-existing application. To remedy these
problems, we defined a new setsockopt() option that allows an
application to explicitly set the form of sockaddr_in addresses returned
by the socket functions. A SIP knowledgeable application that is passed
an open socket from an unknown process may do use the SIP_ADDRFORM
setsockopt() option to "convert" the socket to return AF_SIP form
addresses. Similarly, a SIP knowledgeable application that is about to
pass an open socket to a program that may not be SIP knowledgeable may
"downgrade" the socket to return AF_INET form addresses using the same
setsockopt option.
The macro definition for this new option in <netinet/in.h> is:
#define SIP_ADDRFORM 0x16 /* get/set form of returned addrs */
The SIP_ADDRFORM option is at the IPPROTO_IP level. The only valid
option values are AF_SIP and AF_INET. For example, to convert a socket
to return AF_INET form addresses, a program would call:
int addrform = AF_SIP;
if (setsockopt(s, IPPROTO_IP, SIP_ADDRFORM, (char *) &addrform,
sizeof(addrform)) == -1)
perror("setsockopt SIP_ADDRFORM");
An application may use SIP_ADDRFORM in the getsockopt() function to
learn the form of addresses that will be returned by an open socket.
3.5 IPv4 addresses in AF_SIP form sockaddr_in structures
An application may need to pass 32 bit IPv4 address in a sockaddr_in
structure, but want to set the sin_family field to AF_SIP in order to
set the form of addresses to be returned. To allow for this, we have
defined a convention for storing 32 bit IPv4 addresses in 64 bit SIP
addresses. The 32-bit IPv4 address is stored in the low-order 32 bits
of the SIP address and the high-order 32 bits (i.e. the prefix part) are
set to zero. For example, the following structure:
struct sockaddr_in sin1;
sin1.sin_family = AF_SIP;
sin1.sip_zero = 0;
*((long *) sin1.sip_addr) = 0;
*((long *) &sin1.sip_addr[4]) = inet_addr("192.9.9.1");
And this structure:
struct sockaddr_in sin2;
sin2.sin_family = AF_INET;
sin2.sin_addr.s_addr = inet_addr("192.9.9.1");
bzero(sin2.sin_zero, sizeof(sin_zero);
are alternative ways to represent the same IPv4 address.
All of the socket functions that accept sockaddr_in addresses passed in
as arguments accept IPv4 addresses in the AF_SIP form.
3.6 Flow IDs
The SIP header has a 28 bit field reserved to hold a "flow ID". The
usage of this field has not yet been specified. But in order to allow
application programmers to experiment with SIP flows, we have defined a
setsockopt() option that can be used to set the value to be assigned to
the flow ID field of transmitted SIP packets. So far, we have not
defined any interface for an application to learn the flow ID set in
received SIP packets.
The macro definition for this new option in <netinet/in.h> is:
#define SIP_FLOWID 0x15 /* SIP flow identifier */
The SIP_FLOWID option is at the IPPROTO_IP level. An example of how an
application might use this option is:
int flowid = 0x0f3c91ab; /* random value made up for this example */
if (setsockopt(s, IPPROTO_IP, SIP_FLOWID, (char *) &flowid,
sizeof(flowid)) == -1)
perror("setsockopt SIP_ADDRFORM");
The SIP_FLOWID option can also be used with the getsockopt() option to
retrieve the flow ID value given in the last setsockopt() call.
Since the definition of SIP flows may change as the protocol develops,
this option may also change in the future. Thus application developers
should consider this option "experimental."
3.7 Name-to-address translation functions
We have defined a new function call with the form:
struct hostent *hostname2addr(const char *name, int af,
char *buf, int buflen);
This interface looks the given host name up in the naming service and
returns a list of addresses. The name argument is the name of the host
to look up. The af argument specifies what form of address -- 4-byte
IPv4 or 8-byte SIP address -- to return to the caller in the h_addr_list
field of the hostent structure. The buf argument points to a buffer
that the function can use to store the hostent structure that is
returned. The buflen argument is the size of the buffer. If buf is a
null pointer, the function uses its own static buffer.
If the af argument is AF_INET, hostname2addr() behaves like
gethostbyname(). That is, it returns a hostent structure which includes
an array of 4-byte IPv4 addresses. If AA (SIP address) records are
found, then the low-order 4 bytes of each SIP address are returned. If
only A records are found, then the associated 4-byte IP address is
returned.
If the type argument is AF_SIP, then the h_addr_list field of the
hostent structure contains an array of 8-byte SIP addresses. If AA
records are found, then the full SIP address of each record is returned.
If only A records are found, then each 8-byte address returned holds the
IPv4 address in the low-order 4 bytes and the high-order 4 bytes are set
to zero. (i.e. it uses the convention for storing IPv4 addresses in SIP
addresses defined above).
There was some discussion on the SIP mailing list of some other ways to
cast this function. This proposal allows the application to be simple.
Since it passes in the address family, the application knows the size of
the returned addresses and can unconditionally bcopy() them into
sockaddr_in structures. Also, the semantics of the hostname2addr() when
af is AF_INET lets us implement the existing gethostbyname() function in
terms of the new function.
The gethostbyaddr() function remains unchanged:
struct hostent *gethostbyaddr(const char *addr, int len, int af);
If the af argument is AF_INET, then len must be 4 and addr points to a
4-byte IPv4 address. If af is AF_SIP, then len must be 8 and addr
points to an 8-byte SIP address.
3.8 Address input/output functions
BSD Unix provides two functions -- inet_addr() and inet_ntoa() -- to
convert IPv4 address between binary and printable form. SIP
applications need similar functions. We have defined the following two
functions to convert SIP and IPv4 addresses:
int ascii2addr(long af, char *cp, char *ap);
and
char *addr2ascii(long af, char *ap, char *buf, int buflen)
The first function is used to transform an ascii string into an address
data structure. The af argument specifies that address family of the
address. Currently AF_INET and AF_SIP are supported. The cp argument
points to the ascii string being passed in. The ap argument points to
the 4-byte or 8-byte buffer that the address will be converted into.
If the af argument is AF_INET, the function accepts a string in the
standard IPv4 dotted decimal form:
ddd.ddd.ddd.ddd
Where ddd is a one to three digit decimal number between 0 and 255.
If the af argument is AF_SIP, then the function accepts a string in the
standard IPv4 dotted decimal form given above, or a string in one of the
two standard SIP printing forms:
xxxx:xxxx:ddd.ddd.ddd.ddd
or
xxxx:xxxx:xxxx:xxxx
where xxxx is a 1 to 4 digit hex value and ddd is a 1 to 3 digit decimal
number between 0 and 255. If the string is in the IPv4 dotted decimal
form, the high order 4 bytes of the address buffer pointed to by ap are
set to zero and the low-order 4 bytes are set to the IPv4 address.
Having the AF_SIP variant of the ascii2addr() function accept either
IPv4 addresses or SIP addresses allows an application to easily accept
either form of address from the user.
The second function transforms an address buffer into a printable
string. The af argument specifies the form of the address. This can be
AF_INET or AF_SIP. The ap argument points to a buffer holding a 4-byte
IPv4 address or an 8-byte SIP address. The buf argument points to a
buffer that the function can convert into, and the buflen argument gives
the size of this buffer. If the buf argument is zero, then the function
will convert the address unto a private static buffer of its own. In
either case, the function returns a pointer to the buffer that the
address has been converted into.
The ascii2addr() function returns 0 if the conversion succeeded, and -1
if it failed. The function does not modify the storage pointed to by ap
if the conversion fails. The addr2ascii() function returns a pointer to
the buffer if the conversion succeeded, and -1 if the conversion failed.
These two functions are derived from suggestions by Craig Partridge on
the SIP mailing list. There was some discussion about whether the
buffer that addr2ascii() converts into should be static within the
function() or passed in by the application. In the interface presented
here, we try to provide the best of both worlds.
4. Open Issues
The API changes described here are likely to change as we get experience
writing SIP applications. There are also some issues left unresolved.
Some of the things we need to think about are:
- There is a type defined (in_addr) to represent a 32-bit IPv4
address. Should we define a structure to hold the 64-bit SIP
address? There was some discussion of this on the SIP mailing
list with opinions on both sides.
- The format of the "/etc/hosts" file currently supports only IPv4
addresses. Should we extend the format of the existing file to
handle SIP addresses? Or should we invent a file with a new
name for storing SIP host addresses? Andrew Cherenson suggests
a clever, but ugly, hack to re-use the same file and allow old
and new versions of gethosb* to co-exist: precede SIP lines with
"#SIP", which acts as comment for old versions.
- How do datagram applications participate in path MTU discovery?
- What about the SIOC* ioctl() commands that get and set interface
parameters and manipulate the IP routing table?
- Posix is changing and standardizing the socket interface.
Should we track the posix changes? In particular, 4.3-Reno has
split the 16-bit address family field of the sockaddr struct
into two 8-bit fields: a length field and an address family
field. Should we adopt this here?
- This spec has concentrated on the BSD socket interface. What
about the System V Transport Library Interface (TLI)? Does
anyone really care about TLI?
- The BSD "net-2" release includes setsockopt options to set the
IP TTL. Should we specify that this option sets the SIP hop
limit, or is this just obvious?
5. Security Considerations
Security issues are not discussed in this document.
6. Acknowledgements
Thanks to all who provided feedback to the first revision of this
document, including Christian Huitema, Craig Partridge, Steve Deering,
Andrew Cherenson, Charles Lynn, Ran Atkinson, Erik Nordmark, Glenn
Trewitt, Fred Baker, Robert Elz, and Dean D. Throop.
7. References
[1] Deering, S., "Simple Internet Protocol (SIP) Specification",
Internet Draft November 1992
8. Authors' Address
Robert E. Gilligan
Sun Microsystems, Inc.
2550 Garcia Avenue
Mailstop UMTV05-44
Mountain View, California 94043-1100
415-336-1012
bob.gilligan@eng.sun.com